`timescale 1ns / 1ps

`include "data_width.vh"

// 对每个地址新增一个重用位和重用信号

module rd_src_p_shuffle_block_128_1 #(parameter
    VERTEX_PIPE_NUM = `VERTEX_PIPE_NUM,
    EDGE_PIPE_NUM = `EDGE_PIPE_NUM,
    SRC_P_AWIDTH = `SRC_P_AWIDTH,
    REQ_WIDTH = `REQ_WIDTH,
    TOT_REUSE_WIDTH = `TOT_REUSE_WIDTH, REUSE_WIDTH = `REUSE_WIDTH,
    TOT_EDGE_MASK_WIDTH = `TOT_EDGE_MASK_WIDTH, TOT_ACC_ID_WIDTH = `TOT_ACC_ID_WIDTH,
    DST_ID_DWIDTH = `DST_ID_DWIDTH,
    VERTEX_MASK_WIDTH = `VERTEX_MASK_WIDTH
) (
    input clk,
    input rst,
    input [SRC_P_AWIDTH * EDGE_PIPE_NUM - 1 : 0] front_rd_src_p_addr,
    input front_rd_src_p_valid,
    input [TOT_EDGE_MASK_WIDTH - 1 : 0] front_tot_src_p_mask,
    input [TOT_ACC_ID_WIDTH - 1 : 0] front_tot_acc_id,
    input [DST_ID_DWIDTH * VERTEX_PIPE_NUM - 1 : 0] front_dst_id,
    input [VERTEX_MASK_WIDTH * VERTEX_PIPE_NUM - 1 : 0] front_src_p_mask_r,
    input [VERTEX_PIPE_NUM - 1 : 0] front_dst_data_valid,
    input back_stage_edge_full,
    input back_stage_vertex_full,

    output buffer_full_edge,
    output buffer_full_vertex,
    output [TOT_REUSE_WIDTH - 1 : 0] reuse_info,
    output [EDGE_PIPE_NUM - 1 : 0] reuse_valid,
    output [SRC_P_AWIDTH * EDGE_PIPE_NUM - 1 : 0] rd_src_p_addr,
    output rd_src_p_valid,
    output [TOT_EDGE_MASK_WIDTH - 1 : 0] tot_src_p_mask,
    output [TOT_ACC_ID_WIDTH - 1 : 0] tot_acc_id,
    output [DST_ID_DWIDTH * VERTEX_PIPE_NUM - 1 : 0] dst_id,
    output [VERTEX_MASK_WIDTH * VERTEX_PIPE_NUM - 1 : 0] src_p_mask_r,
    output [VERTEX_PIPE_NUM - 1 : 0] dst_data_valid);

    wire edge_buffer_full;
    wire mask_buffer_full, mask_buffer_empty;
    wire [VERTEX_PIPE_NUM - 1 : 0] dst_buffer_full, dst_buffer_empty;
    wire any_front_dst_data_valid;

    assign any_front_dst_data_valid = |front_dst_data_valid;
    assign buffer_full_edge = edge_buffer_full;
    assign buffer_full_vertex = |dst_buffer_full;

    rd_src_p_shuffle_block_128_1_edge E1 (
        .clk(clk), .rst(rst),
        .front_rd_src_p_addr(front_rd_src_p_addr), .front_rd_src_p_valid(front_rd_src_p_valid),
        .back_stage_edge_full(back_stage_edge_full),

        .buffer_full(edge_buffer_full),
        .rd_src_p_addr(rd_src_p_addr), .rd_src_p_valid(rd_src_p_valid),
        .reuse_info(reuse_info), .reuse_valid(reuse_valid));

    rd_src_p_shuffle_block_128_1_mask M1 (
        .clk(clk), .rst(rst),
        .front_tot_src_p_mask(front_tot_src_p_mask), .front_tot_acc_id(front_tot_acc_id),
        .any_front_dst_data_valid(any_front_dst_data_valid), .back_stage_vertex_full(back_stage_vertex_full),

        .buffer_empty(mask_buffer_empty), .buffer_full(mask_buffer_full),
        .tot_src_p_mask(tot_src_p_mask), .tot_acc_id(tot_acc_id));

    generate
        genvar i;
        for (i = 0; i < VERTEX_PIPE_NUM; i = i + 1) begin : M9_1_BLOCK_1
            rd_src_p_shuffle_block_128_1_vertex_single V (
                .clk(clk), .rst(rst),
                .front_dst_id(front_dst_id[(i + 1) * DST_ID_DWIDTH - 1 : i * DST_ID_DWIDTH]),
                .front_src_p_mask_r(front_src_p_mask_r[(i + 1) * VERTEX_MASK_WIDTH - 1 : i * VERTEX_MASK_WIDTH]),
                .front_dst_data_valid(front_dst_data_valid[i]),
                .any_front_dst_data_valid(any_front_dst_data_valid), .back_stage_vertex_full(back_stage_vertex_full),

                .buffer_empty(dst_buffer_empty[i]), .buffer_full(dst_buffer_full[i]),
                .dst_id(dst_id[(i + 1) * DST_ID_DWIDTH - 1 : i * DST_ID_DWIDTH]),
                .src_p_mask_r(src_p_mask_r[(i + 1) * VERTEX_MASK_WIDTH - 1 : i * VERTEX_MASK_WIDTH]),
                .dst_data_valid(dst_data_valid[i]));
        end
    endgenerate

/*
    rd_src_p_shuffle_block_128_1_vertex_single V1 (
        .clk(clk), .rst(rst),
        .front_dst_id(front_dst_id_1), .front_src_p_mask_r(front_src_p_mask_r_1), .front_dst_data_valid(front_dst_data_valid_1),
        .any_front_dst_data_valid(any_front_dst_data_valid), .back_stage_vertex_full(back_stage_vertex_full),

        .buffer_empty(dst_buffer_empty[0]), .buffer_full(dst_buffer_full[0]),
        .dst_id(dst_id_1), .src_p_mask_r(src_p_mask_r_1), .dst_data_valid(dst_data_valid_1));
*/

endmodule

module rd_src_p_shuffle_block_128_1_edge #(parameter
    EDGE_PIPE_NUM = `EDGE_PIPE_NUM,
    TOT_REUSE_WIDTH = `TOT_REUSE_WIDTH, REUSE_WIDTH = `REUSE_WIDTH,
    SRC_P_AWIDTH = `SRC_P_AWIDTH
) (
    input clk,
    input rst,
    input [SRC_P_AWIDTH * EDGE_PIPE_NUM - 1 : 0] front_rd_src_p_addr,
    input front_rd_src_p_valid,
    input back_stage_edge_full,

    output buffer_full,
    output reg [SRC_P_AWIDTH * EDGE_PIPE_NUM - 1 : 0] rd_src_p_addr,
    output reg rd_src_p_valid,
    output [TOT_REUSE_WIDTH - 1 : 0] reuse_info,
    output [EDGE_PIPE_NUM - 1 : 0] reuse_valid);

    reg buffer_full_reg;

    assign buffer_full = buffer_full_reg;

    always @ (posedge clk) begin
        if (rst) begin
            rd_src_p_addr <= 0;
            rd_src_p_valid <= 1'b0;
            buffer_full_reg <= 1'b1;
        end
        else begin
            rd_src_p_addr <= front_rd_src_p_addr;
            rd_src_p_valid <= front_rd_src_p_valid;
            buffer_full_reg <= back_stage_edge_full;
        end
    end

    generate
        genvar i;
        for (i = 0; i < EDGE_PIPE_NUM; i = i + 1) begin : M9_1_BLOCK_2
            rd_src_p_shuffle_block_128_1_edge_reuse #(.LOC(i)) R (
                .clk(clk), .rst(rst),
                .front_rd_src_p_addr(front_rd_src_p_addr),

                .reuse_info_single(reuse_info[REUSE_WIDTH * (i + 1) - 1 : REUSE_WIDTH * i]),
                .reuse_valid_single(reuse_valid[i]));
        end
    endgenerate

endmodule

module rd_src_p_shuffle_block_128_1_edge_reuse #(parameter
    LOC = 6'b000000,
    SRC_P_AWIDTH = `SRC_P_AWIDTH,
    EDGE_PIPE_NUM = `EDGE_PIPE_NUM,
    REUSE_WIDTH = `REUSE_WIDTH
) (
    input clk,
    input rst,
    input [SRC_P_AWIDTH * EDGE_PIPE_NUM - 1 : 0] front_rd_src_p_addr,

    output reg [REUSE_WIDTH - 1 : 0] reuse_info_single,
    output reg reuse_valid_single);

    wire [EDGE_PIPE_NUM - 1 : 0] reuse_valid_i;

    generate
        genvar i;
        for (i = 0; i < LOC; i = i + 1) begin : M9_1_BLOCK_3
            assign reuse_valid_i[i] = (front_rd_src_p_addr[(i + 1) * SRC_P_AWIDTH - 1 : i * SRC_P_AWIDTH] == front_rd_src_p_addr[(LOC + 1) * SRC_P_AWIDTH - 1 : LOC * SRC_P_AWIDTH]);
        end
        // 不对顺序高于自身的地址产生复用信息
        for (i = LOC; i < EDGE_PIPE_NUM; i = i + 1) begin : M9_1_BLOCK_4
            assign reuse_valid_i[i] = 1'b0;
        end
    endgenerate

    always @ (posedge clk) begin
        if (rst) begin
            reuse_info_single <= 0;
            reuse_valid_single <= 1'b0;
        end
        else begin
            // 保证只会复用到最低顺序的相同地址
            casex (reuse_valid_i)
                32'b00000000000000000000000000000000: begin
                    reuse_info_single <= 0;
                    reuse_valid_single <= 1'b0;
                end
                32'bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1: begin
                    reuse_info_single <= 5'b00000;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx10: begin
                    reuse_info_single <= 5'b00001;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxxxxxxxxxxxxxxxxxxxxxxxx100: begin
                    reuse_info_single <= 5'b00010;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxxxxxxxxxxxxxxxxxxxxxxx1000: begin
                    reuse_info_single <= 5'b00011;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxxxxxxxxxxxxxxxxxxxxxx10000: begin
                    reuse_info_single <= 5'b00100;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxxxxxxxxxxxxxxxxxxxxx100000: begin
                    reuse_info_single <= 5'b00101;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxxxxxxxxxxxxxxxxxxxx1000000: begin
                    reuse_info_single <= 5'b00110;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxxxxxxxxxxxxxxxxxxx10000000: begin
                    reuse_info_single <= 5'b00111;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxxxxxxxxxxxxxxxxxx100000000: begin
                    reuse_info_single <= 5'b01000;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxxxxxxxxxxxxxxxxx1000000000: begin
                    reuse_info_single <= 5'b01001;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxxxxxxxxxxxxxxxx10000000000: begin
                    reuse_info_single <= 5'b01010;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxxxxxxxxxxxxxxx100000000000: begin
                    reuse_info_single <= 5'b01011;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxxxxxxxxxxxxxx1000000000000: begin
                    reuse_info_single <= 5'b01100;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxxxxxxxxxxxxx10000000000000: begin
                    reuse_info_single <= 5'b01101;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxxxxxxxxxxxx100000000000000: begin
                    reuse_info_single <= 5'b01110;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxxxxxxxxxxx1000000000000000: begin
                    reuse_info_single <= 5'b01111;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxxxxxxxxxx10000000000000000: begin
                    reuse_info_single <= 5'b10000;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxxxxxxxxx100000000000000000: begin
                    reuse_info_single <= 5'b10001;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxxxxxxxx1000000000000000000: begin
                    reuse_info_single <= 5'b10010;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxxxxxxx10000000000000000000: begin
                    reuse_info_single <= 5'b10011;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxxxxxx100000000000000000000: begin
                    reuse_info_single <= 5'b10100;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxxxxx1000000000000000000000: begin
                    reuse_info_single <= 5'b10101;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxxxx10000000000000000000000: begin
                    reuse_info_single <= 5'b10110;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxxx100000000000000000000000: begin
                    reuse_info_single <= 5'b10111;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxxx1000000000000000000000000: begin
                    reuse_info_single <= 5'b11000;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxxx10000000000000000000000000: begin
                    reuse_info_single <= 5'b11001;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxxx100000000000000000000000000: begin
                    reuse_info_single <= 5'b11010;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxxx1000000000000000000000000000: begin
                    reuse_info_single <= 5'b11011;
                    reuse_valid_single <= 1'b1;
                end
                32'bxxx10000000000000000000000000000: begin
                    reuse_info_single <= 5'b11100;
                    reuse_valid_single <= 1'b1;
                end
                32'bxx100000000000000000000000000000: begin
                    reuse_info_single <= 5'b11101;
                    reuse_valid_single <= 1'b1;
                end
                32'bx1000000000000000000000000000000: begin
                    reuse_info_single <= 5'b11110;
                    reuse_valid_single <= 1'b1;
                end
                32'b10000000000000000000000000000000: begin
                    reuse_info_single <= 5'b11111;
                    reuse_valid_single <= 1'b1;
                end
            endcase
        end
    end

endmodule

module rd_src_p_shuffle_block_128_1_mask #(parameter
    TOT_EDGE_MASK_WIDTH = `TOT_EDGE_MASK_WIDTH, TOT_ACC_ID_WIDTH = `TOT_ACC_ID_WIDTH
    ) (
        input clk,
        input rst,
        input [TOT_EDGE_MASK_WIDTH - 1 : 0] front_tot_src_p_mask,
        input [TOT_ACC_ID_WIDTH - 1 : 0] front_tot_acc_id,
        input any_front_dst_data_valid,
        input back_stage_vertex_full,

        output buffer_empty,
        output buffer_full,
        output [TOT_EDGE_MASK_WIDTH - 1 : 0] tot_src_p_mask,
        output [TOT_ACC_ID_WIDTH - 1 : 0] tot_acc_id);

    tot_edge_mask_fifo TEM1 (
        .clk(clk), .srst(rst),
        .din(front_tot_src_p_mask), .wr_en(any_front_dst_data_valid && !rst), .rd_en(!(buffer_empty || back_stage_vertex_full) && !rst),

        .dout(tot_src_p_mask), .empty(buffer_empty), .prog_full(buffer_full));

    tot_acc_id_fifo TAI1 (
        .clk(clk), .srst(rst),
        .din(front_tot_acc_id), .wr_en(any_front_dst_data_valid && !rst), .rd_en(!(buffer_empty || back_stage_vertex_full) && !rst),

        .dout(tot_acc_id));

endmodule

module rd_src_p_shuffle_block_128_1_vertex_single #(parameter
    DST_ID_DWIDTH = `DST_ID_DWIDTH, VERTEX_MASK_WIDTH = `VERTEX_MASK_WIDTH
    ) (
        input clk,
        input rst,
        input [DST_ID_DWIDTH - 1 : 0] front_dst_id,
        input [VERTEX_MASK_WIDTH - 1 : 0] front_src_p_mask_r,
        input front_dst_data_valid,
        input any_front_dst_data_valid,
        input back_stage_vertex_full,
        
        output buffer_empty,
        output buffer_full,
        output [DST_ID_DWIDTH - 1 : 0] dst_id,
        output [VERTEX_MASK_WIDTH - 1 : 0] src_p_mask_r,
        output dst_data_valid);

    wire tmp_dst_data_valid_1, tmp_dst_data_valid_2;

    dst_id_fifo DI1 (
        .clk(clk), .srst(rst),
        .din(front_dst_id), .wr_en(any_front_dst_data_valid && !rst), .rd_en(!(buffer_empty || back_stage_vertex_full) && !rst),

        .dout(dst_id), .empty(buffer_empty), .prog_full(buffer_full));

    vertex_mask_fifo VM1 (
        .clk(clk), .srst(rst),
        .din(front_src_p_mask_r), .wr_en(any_front_dst_data_valid && !rst), .rd_en(!(buffer_empty || back_stage_vertex_full) && !rst),

        .dout(src_p_mask_r));

    valid_fifo DDV1 (
        .clk(clk), .srst(rst),
        .din(front_dst_data_valid), .wr_en(any_front_dst_data_valid && !rst), .rd_en(!(buffer_empty || back_stage_vertex_full) && !rst),

        .dout(tmp_dst_data_valid_1), .valid(tmp_dst_data_valid_2));

    assign dst_data_valid = tmp_dst_data_valid_1 && tmp_dst_data_valid_2;

endmodule